using System.Collections.Generic;
using UnityEngine;

namespace LS.GameKit
{
    public class MapBlockViewer2D : MonoBehaviour
    {
        private static int s_UnitId = 0;

        public bool positionRoundToInt = true;
        public bool sizeRoundToInt = true;
        [Range(0, 1)] public float sketchAlpha = 0.5f;
        public float whiteFrameSizeOffset = 10;

        [SerializeField] private SpriteRenderer m_WhiteFrameRenderer;

        [SerializeField] private SpriteRenderer m_InnerFillerRenderer;

        [SerializeField] private SpriteRenderer m_SketchMap;

        private ComplexTiledSpriteController m_WhiteFrameController;
        private ComplexTiledSpriteController m_InnerFillerController;

        public SpriteRenderer WhiteFrameRenderer
        {
            get { return m_WhiteFrameRenderer; }
        }

        public SpriteRenderer InnerFillerRenderer
        {
            get { return m_InnerFillerRenderer; }
        }

        public SpriteRenderer SketchMap
        {
            get { return m_SketchMap; }
        }

        public ComplexTiledSpriteController WhiteFrameController
        {
            get { return m_WhiteFrameController; }
        }

        public ComplexTiledSpriteController InnerFillerController
        {
            get { return m_InnerFillerController; }
        }

        private void Awake()
        {
            m_WhiteFrameController = m_WhiteFrameRenderer?.GetComponent<ComplexTiledSpriteController>();
            m_InnerFillerController = m_InnerFillerRenderer?.GetComponent<ComplexTiledSpriteController>();

            MapBlockViewer2DUtility.ResetWhiteFrame(m_WhiteFrameRenderer, m_WhiteFrameController);
            MapBlockViewer2DUtility.ResetWhiteFrame(m_InnerFillerRenderer, m_InnerFillerController);
            MapBlockViewer2DUtility.ResetSketchMap(m_SketchMap);
        }

        private void Start()
        {
            HideWhiteFrame();
            HideInnerFiller();
        }

        public void Show(Vector3 position, Vector2 size, Sprite sketch = null, Color[] innerColors = null)
        {
            ShowWhiteFrame(position, size);
            ShowInnerFiller(position, size, innerColors);
            ShowSketchMap(position, size, sketch);
        }

        public void Hide()
        {
            HideWhiteFrame();
            HideInnerFiller();
            HideSketchMap();
        }

        public void ShowWhiteFrame()
        {
            if (m_WhiteFrameRenderer == null)
                return;

            m_WhiteFrameRenderer.enabled = true;
        }

        public void ShowWhiteFrame(Vector3 position, Vector2 size)
        {
            if (m_WhiteFrameRenderer == null)
                return;

            m_WhiteFrameRenderer.enabled = true;
            position -= (Vector3)size * 0.5f;

            if (whiteFrameSizeOffset != 0)
            {
                Vector3 sizeOffset = new Vector3(whiteFrameSizeOffset, whiteFrameSizeOffset);
                position -= sizeOffset * 0.5f;
                size += (Vector2)sizeOffset;
            }

            Vector3 finalPosition = position;
            Vector2 finalSize = size;

            if (positionRoundToInt)
            {
                finalPosition = Vector3Int.RoundToInt(finalPosition);
            }

            if (sizeRoundToInt)
            {
                finalSize.Set(
                    Mathf.RoundToInt(size.x),
                    Mathf.RoundToInt(size.y)
                );
            }

            m_WhiteFrameRenderer.transform.position = finalPosition;
            m_WhiteFrameRenderer.size = finalSize;
        }

        public void HideWhiteFrame()
        {
            if (m_WhiteFrameRenderer == null)
                return;

            m_WhiteFrameRenderer.enabled = false;
        }

        public void ShowInnerFiller()
        {
            if (m_InnerFillerRenderer == null)
                return;

            m_InnerFillerRenderer.enabled = true;
        }

        public void ShowInnerFiller(Vector3 position, Vector2 size)
        {
            if (m_InnerFillerRenderer == null)
                return;

            m_InnerFillerRenderer.enabled = true;
            int sx = (int)size.x;
            int sy = (int)size.y;
            Color[] cols = new Color[sx * sy];
            for (int i = 0; i < cols.Length; i++)
            {
                cols[i] = Color.white;
            }

            ShowInnerFiller(position, size, cols);
        }

        public void ShowInnerFiller(Vector3 position, Vector2 size, Color[] colors)
        {
            if (m_InnerFillerRenderer == null)
                return;
            position -= (Vector3)size * 0.5f;
            Vector3 finalPosition = position;
            Vector2 finalSize = size;
            if (positionRoundToInt)
            {
                finalPosition = Vector3Int.RoundToInt(finalPosition);
            }

            if (sizeRoundToInt)
            {
                finalSize.Set(
                    Mathf.RoundToInt(size.x),
                    Mathf.RoundToInt(size.y)
                );
            }

            m_InnerFillerRenderer.enabled = true;
            m_InnerFillerRenderer.transform.position = finalPosition;
            m_InnerFillerRenderer.size = finalSize;

            int sizeX = Mathf.RoundToInt(size.x);
            int sizeY = Mathf.RoundToInt(size.y);

            if (colors == null)
            {
                colors = new Color[sizeX * sizeY];
                Color defaultColor = new Color(1, 1, 1, 0);
                for (int i = 0; i < colors.Length; i++)
                {
                    colors[i] = defaultColor;
                }
            }

            if (m_InnerFillerController != null)
            {
                for (int y = 0; y < sizeY; y++)
                {
                    for (int x = 0; x < sizeX; x++)
                    {
                        m_InnerFillerController.SetColor(x, y, colors[y * sizeX + x]);
                    }
                }
            }
        }

        public void HideInnerFiller()
        {
            if (m_InnerFillerRenderer == null)
                return;

            m_InnerFillerRenderer.enabled = false;
        }

        public void ShowSketchMap(Sprite sprite, bool stillSetupIfSpriteIsNull = false)
        {
            if (m_SketchMap == null)
                return;

            m_SketchMap.enabled = true;
            if (sprite != null || stillSetupIfSpriteIsNull)
                m_SketchMap.sprite = sprite;
            m_SketchMap.color = m_SketchMap.sprite == null ? new Color(1, 1, 1, 0) : new Color(1, 1, 1, sketchAlpha);
        }

        public void ShowSketchMap()
        {
            if (m_SketchMap == null)
                return;

            m_SketchMap.enabled = true;
            m_SketchMap.color = m_SketchMap.sprite == null ? new Color(1, 1, 1, 0) : new Color(1, 1, 1, sketchAlpha);
        }

        public void ShowSketchMap(Vector3 position, Vector2 size, Sprite sprite = null,
            bool stillSetupIfSpriteIsNull = false)
        {
            if (m_SketchMap == null)
                return;
            Vector2 pivot = sprite.pivot / sprite.rect.size;
            Vector3 finalPosition = position - new Vector3(size.x * pivot.x, size.y * pivot.y, 0);
            Vector2 finalSize = size;
            if (positionRoundToInt)
            {
                finalPosition = Vector3Int.RoundToInt(finalPosition);
            }

            if (sizeRoundToInt)
            {
                finalSize = Vector2Int.RoundToInt(finalSize);
            }

            m_SketchMap.enabled = true;

            if (sprite != null || stillSetupIfSpriteIsNull)
                m_SketchMap.sprite = sprite;
            m_SketchMap.color = m_SketchMap.sprite == null ? new Color(1, 1, 1, 0) : new Color(1, 1, 1, sketchAlpha);

            m_SketchMap.transform.position = finalPosition + new Vector3(finalSize.x * pivot.x, finalSize.y * pivot.y, 0);
            m_SketchMap.size = finalSize;
        }

        public void HideSketchMap()
        {
            if (m_SketchMap == null)
                return;

            m_SketchMap.enabled = false;
        }

        public struct BlockColorSet
        {
            public Vector2Int position;
            public Color color;

            public BlockColorSet(Vector2Int position, Color color)
            {
                this.position = position;
                this.color = color;
            }
        }
    }
}